package com.wonders.app.file.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wonders.app.bean.NodeBean;
import com.wonders.app.file.dao.NodeDao;
import com.wonders.app.file.service.NodeService;
import com.wonders.app.utils.ConfigPathUtil;
import com.wonders.common.exception.RRException;
import com.wonders.common.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class NodeServiceImpl extends ServiceImpl<NodeDao, NodeBean> implements NodeService {


    @Autowired
    ConfigPathUtil configPathUtil ;


    @Override
    public List<NodeBean> selectNodes(NodeBean nodeBean) {
        System.out.println("递归 "+nodeBean.toString());
      return getTreeDataRecursion(Math.toIntExact(nodeBean.getpId()));
    }

    @Override
    public List<NodeBean> getCenters(NodeBean nodeBean) {
        QueryWrapper<NodeBean> wrapper = new QueryWrapper<>();
        wrapper.eq("p_id", nodeBean.getId());
        return list(wrapper);
    }


    @Override
    public NodeBean getOneData(NodeBean nodeBean) {
        return getById(nodeBean.getId());
    }


    @Override
    public Boolean insertOneData(NodeBean nodeBean) {

        return save(nodeBean);
    }

    @Override
    public Boolean upDateOneDataById(NodeBean nodeBean) {
        return updateById(nodeBean);
    }

    @Override
    public Boolean deleteOneDataById(NodeBean nodeBean) {
        return removeById(nodeBean.getId());
    }


    private List<NodeBean> getTreeDataRecursion(int pId){
        // 递归方法，调用此方法时候，将 0 传入，0代表一级菜单
        // 获取所有的子级
        QueryWrapper<NodeBean> wrapper = new QueryWrapper<>();
        wrapper.eq("p_id", pId);
        List<NodeBean> nodes = list(wrapper);

        // 判断子级是否还有子级
        if (nodes == null || nodes.size() < 1) {
            // 如果没有子级则返回空
            return null;
        }
        for (NodeBean node : nodes) {
            // 递归方法，自己调用自己
            List<NodeBean> treeDataRecursion = getTreeDataRecursion(Math.toIntExact(node.getId()));
            // 将子级放入父级中
            node.setNodeBeanList(treeDataRecursion);

        }
        return nodes;
    }


    /***
     *  清空文件夹
     *
     */
    public  void clearDir(String path) {
        File file = new File(path);
        System.out.println("清空文件夹.......");
        File[] files = file.listFiles();
        if (files!=null){
            System.out.println("有多少文件"+files.length);
            if (files.length>0) {
                for (File f : files) {
                    boolean delete = f.delete();
//                    System.out.println(delete+"删除状态"+f.getName());
                }
            }
        }

    }


    /**
     * 上传文件(文档+文档中的图片)
     *
     * @param
     */
    public  R upload(MultipartFile upload,long id) {
        System.out.println("上传文件-> 图片");

        Map<String, Object> map = new HashMap<>();
        //根目录
//        String path = "/data/docker/nginx/html/";
        String path = configPathUtil.getRootPath();
        System.out.println(path+upload.getOriginalFilename()+"=="+getPath());
        // 使用fileupload组件完成文件上传
        String uuId = getPath();
        //上传判断文件，不需要uuid了，根据文件名
        File file =  new File(path+upload.getOriginalFilename());
        if (file.exists()){
            boolean delete = file.delete();
        }
        try {
            //是MD文件
            if (upload.getOriginalFilename().contains(".md")){
                upload.transferTo(new File(path,upload.getOriginalFilename()));
                map.put("result","success");
            }else {
                // 上传图片的话，需要把图片的路径保存到数据库
                NodeBean nodeBean = getById(id);
                String url = nodeBean.getUrl();
               upload.transferTo(new File(path,uuId+"-"+upload.getOriginalFilename()));

                if (url!=null){
                    int i = baseMapper.updateImgUrl(id, url+","+uuId+"-"+upload.getOriginalFilename());
                    System.out.println("连接"+url+","+uuId+"-"+upload.getOriginalFilename());
                    System.out.println(i);
                }else {
                    int i = baseMapper.updateImgUrl(id, ","+""+uuId+"-"+upload.getOriginalFilename());
                    System.out.println(i);
                }


                map.put("result", ","+uuId+"-"+upload.getOriginalFilename());
            }
        } catch (IOException e) {
            throw new RRException("上传文件异常" + e.getMessage());
        }

        return R.ok(map);

    }


    /**
     * 下载文件 一个文件==
     */
    public R downloadOneFile(String downloadFile) {
        System.out.println("开始下载文件名字是 "+downloadFile);
//        String path = "/data/docker/nginx/html/" + downloadFile;
        String path = configPathUtil.getRootPath() + downloadFile;
        String pathTemp = "/temp/" + downloadFile;
        Map<String, Object> map = new HashMap<>();

        File file = new File(path);
        File fileTemp = new File(pathTemp);
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            OutputStream os = new FileOutputStream(fileTemp);
            InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
            BufferedReader br = new BufferedReader(reader);
            String line;
            while ((line = br.readLine()) != null) {
                line += '\n';
                os.write(line.getBytes());
                os.flush();
            }
            br.close();
            reader.close();
        } catch (Exception e) {
            throw new RRException("下载文件异常" + e.getMessage());
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return R.ok(map);

    }


    //返回值暂时没用到
    public R downloadOneImg(String downloadFile) {
        System.out.println("开始下载图片是 名字是 "+downloadFile);
//        String path = "/data/docker/nginx/html/" + downloadFile;
        String path = configPathUtil.getRootPath() + downloadFile;
        String pathTemp = "/temp/" + downloadFile;
        Map<String, Object> map = new HashMap<>();

        // 实现文件下载
        byte[] buffer = new byte[1024];
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            fis = new FileInputStream(path);
            bis = new BufferedInputStream(fis);
            os = new FileOutputStream(pathTemp);
            int n;
            while ((n = bis.read(buffer, 0, 1024)) != -1) {
                os.write(buffer, 0, n);
                os.flush();
            }
        } catch (Exception e) {
            throw new RRException("下载文件异常"+e.getMessage());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return R.ok(map);

    }



    /**
     *  将指定节点下的 所有文件下载到 临时目录中
     * @param pId
     */
    public  void  downloadToTemp(long pId){
        //根目录
//        String path = "/data/docker/nginx/html/";
        String path = configPathUtil.getRootPath();
        // 递归方法，调用此方法时候，将 0 传入，0代表一级菜单
        // 获取所有的子级
        QueryWrapper<NodeBean> wrapper = new QueryWrapper<>();
        wrapper.eq("p_id", pId);

        //把自己本身的下载(logo头像信息)忘记了
        NodeBean nodeSelf = getById(pId);
        if (!StrUtil.isEmpty(nodeSelf.getUrl())){
            System.out.println("该node的url不是空，要遍历下载");
            String result[] = (nodeSelf.getUrl().split(","));
            for (String str:result) {
                System.out.println("遍历的字符串 "+str);
                if(!str.isEmpty()){
                    downloadOneImg(str);
                }
            }
        }

        //查询到所有的父亲节点下的 一级菜单（就是所有的中心）
        List<NodeBean> nodes = list(wrapper);
        // 判断子级是否还有子级
        if (nodes == null || nodes.size() < 1) {
            // 如果没有子级则返回空
            return ;
        }
        for (NodeBean node : nodes) {
            System.out.println("遍历节点"+node.getType()+node.getId());
            //下载文件
//            if (node.getType()!=null){
                // 如果文件，就是不是json结构
//            if (!node.getType().equals("ci")&&!StrUtil.isEmpty(node.getType())){
//                System.out.println("文件类型"+node.toString());
                //判断该文件是否存在
                File file =  new File(path+node.getId()+"-"+node.getName()+".md");
                if (file.exists()){
                    downloadOneFile(node.getId()+"-"+node.getName()+".md");
                }
//                System.out.println("");
                //下载该文件包含的图片
                if (!StrUtil.isEmpty(node.getUrl())){
                    System.out.println("该node的url不是空，要遍历下载==完整的串是 "+node.getUrl());
                    String result[] = (node.getUrl().split(","));
                    for (String str:result) {
                        System.out.println("遍历的字符串 "+str);
                        if(!str.isEmpty()){
                          downloadOneImg(str);
                        }
                    }
                }
//            }
//            }
            // 递归方法，自己调用自己
             downloadToTemp(Math.toIntExact(node.getId()));
            // 递归方法，自己调用自己
//            List<NodeBean> treeDataRecursion =  downloadToTemp(Math.toIntExact(node.getId()));
            // 将子级放入父级中
//            node.setNodeBeanList(treeDataRecursion);
        }

        compress("/temp",configPathUtil.getRootPath()+"zip/raw.zip");

        //返回的是子节点的信息
//        return nodes ;

    }




        /**
     *   响应返回文件 流。
     * @param downloadFile  下载的文件
     */
    public  void downloadStream2(String downloadFile, HttpServletResponse response)  {
//        String path = "/data/docker/nginx/html/"+downloadFile ;
        String path = configPathUtil.getRootPath()+downloadFile ;
//        Map<String, Object> map = new HashMap<>();

        // 配置文件下载
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");
        // 下载文件能正常显示中文
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downloadFile, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RRException("下载文件异常"+e.getMessage());
        }
        // 实现文件下载
        byte[] buffer = new byte[1024];
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            fis = new FileInputStream(path);
            bis = new BufferedInputStream(fis);
            OutputStream os = response.getOutputStream();
            int n;
            while ((n = bis.read(buffer, 0, 1024)) != -1) {
                os.write(buffer, 0, n);
                os.flush();
            }
        } catch (Exception e) {
            throw new RRException("下载文件异常"+e.getMessage());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }



    static final int BUFFER = 8192;

    public  void compress(String srcPath , String dstPath) {
        File srcFile = new File(srcPath);
        File dstFile = new File(dstPath);
        if (!srcFile.exists()) {
            throw new RRException(srcPath + "不存在！");
//            throw new FileNotFoundException(srcPath + "不存在！");
        }

        FileOutputStream out = null;
        ZipOutputStream zipOut = null;
        try {
            out = new FileOutputStream(dstFile);
            CheckedOutputStream cos = new CheckedOutputStream(out,new CRC32());
            zipOut = new ZipOutputStream(cos);
            String baseDir = "";
            compress(srcFile, zipOut, baseDir);
        }catch (Exception e){
            throw new RRException("压缩异常"+e.getMessage());
        }
        finally {
            if(null != zipOut){
                try {
                    zipOut.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                out = null;
            }

            if(null != out){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private  void compress(File file, ZipOutputStream zipOut, String baseDir) throws IOException{
        if (file.isDirectory()) {
            compressDirectory(file, zipOut, baseDir);
        } else {
            compressFile(file, zipOut, baseDir);
        }
    }

    /** 压缩一个目录 */
    private  void compressDirectory(File dir, ZipOutputStream zipOut, String baseDir) throws IOException{
        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            compress(files[i], zipOut, baseDir + dir.getName() + "/");
        }
    }

    /** 压缩一个文件 */
    private  void compressFile(File file, ZipOutputStream zipOut, String baseDir)  throws IOException{
        if (!file.exists()){
            return;
        }

        BufferedInputStream bis = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(file));
            ZipEntry entry = new ZipEntry(baseDir + file.getName());
            zipOut.putNextEntry(entry);
            int count;
            byte data[] = new byte[BUFFER];
            while ((count = bis.read(data, 0, BUFFER)) != -1) {
                zipOut.write(data, 0, count);
            }

        }finally {
            if(null != bis){
                bis.close();
            }
        }
    }


    /**
     * 文件路径
     * @return 返回上传路径
     */
    public String getPath() {
        //生成uuid
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        return uuid ;
    }


}
